from classfile.class_reader import MethodCodeReader
from classfile.constant import ConstantHelper
from heap.class_klass import Klass
from heap.constant_pool import KlassConstantPool
from heap.jstring import JString
from heap.system_ref import ClassRef
from insts.inst import NoOperandInstruction, Index8Instruction, Index16Instruction
from jthread.frame import JFrame


# 常量值 push到操作数栈
class Constant(NoOperandInstruction):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = None
        self.operand = None

    def execute(self, frame: JFrame):
        if self.kind == 'int':
            frame.getOperandStack().pushInt(self.operand)
        elif self.kind == 'float':
            frame.getOperandStack().pushFloat(self.operand)
        elif self.kind == 'long':
            frame.getOperandStack().pushLong(self.operand)
        elif self.kind == 'double':
            frame.getOperandStack().pushDouble(self.operand)
        else:
            frame.getOperandStack().pushRef(self.operand)
class ACONST_NULL(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'ref'
        self.operand = None

class ICONST_M1(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'int'
        self.operand = -1


class ICONST_0(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'int'
        self.operand = 0


class ICONST_1(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'int'
        self.operand = 1


class ICONST_2(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'int'
        self.operand = 2


class ICONST_3(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'int'
        self.operand = 3


class ICONST_4(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'int'
        self.operand = 4


class ICONST_5(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'int'
        self.operand = 5


class LCONST_0(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'long'
        self.operand = 0


class LCONST_1(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'long'
        self.operand = 1


class FCONST_0(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'float'
        self.operand = 0.0


class FCONST_1(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'float'
        self.operand = 1.0


class FCONST_2(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'float'
        self.operand = 2.0


class DCONST_0(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'double'
        self.operand = 0.0


class DCONST_1(Constant):

    def __init__(self, opcode):
        super().__init__(opcode)
        self.kind = 'double'
        self.operand = 1.0


# byte short 整数值 push到操作数栈
class BIPUSH(Index8Instruction):
    def execute(self, frame: JFrame):
        frame.getOperandStack().pushInt(self.index)


class SIPUSH(Index16Instruction):
    def execute(self, frame: JFrame):
        frame.getOperandStack().pushInt(self.index)


# 什么都不做的指令
class Nop(NoOperandInstruction):
    def execute(self, frame: JFrame):
        pass


class LDC(Index8Instruction):
    def execute(self, frame: JFrame):
        klass: Klass = frame.getJMethod().getKlass()
        stack = frame.getOperandStack()
        pool: KlassConstantPool = klass.getConstantPool()
        constant = pool.getConstant2(index=self.index)
        if type(constant) == map:
            if constant['tag'] == ConstantHelper.CONSTANT_INTEGER:  # int
                stack.pushInt(constant['value'])
            elif constant['tag'] == ConstantHelper.CONSTANT_FLOAT:  # float
                stack.pushFloat(constant['value'])
            elif (constant['tag'] == ConstantHelper.CONSTANT_STRING
                  or constant.tag == ConstantHelper.CONSTANT_UTF_8):  # String
                jstr = JString.internal(klass.getClassLoader(), constant['value'])
                stack.pushRef(jstr)
                # 这里应该是pushRef，因为常量池中的字符串常量是引用类型
            else:
                raise ValueError('Unknown constant type: %s' % constant['tag'])
        else:
            if type(constant) == ClassRef:  # class
                ref = constant.resolveClass().getHeapClass()
                stack.pushRef(ref)
            else:
                raise ValueError('Unknown constant type: %s' % type(constant))


class LDC_W2(Index16Instruction):

    def execute(self, frame: JFrame):
        klass: Klass = frame.getJMethod().getKlass()
        stack = frame.getOperandStack()
        pool: KlassConstantPool = klass.getConstantPool()
        constant = pool.getConstant2(index=self.index)
        if type(constant) == map:
            if constant['tag'] == ConstantHelper.CONSTANT_LONG:  # long
                stack.pushLong(constant['value'])
            elif constant['tag'] == ConstantHelper.CONSTANT_DOUBLE:  # double
                stack.pushDouble(constant['value'])
            elif (constant['tag'] == ConstantHelper.CONSTANT_STRING
                  or constant.tag == ConstantHelper.CONSTANT_UTF_8):  # String
                jstr = JString.internal(klass.getClassLoader(), constant['value'])
                stack.pushRef(jstr)
                # 这里应该是pushRef，因为常量池中的字符串常量是引用类型
            else:
                raise ValueError('Unknown constant type: %s' % constant['tag'])
        else:
            if type(constant) == ClassRef:  # class
                ref = constant.resolveClass().getHeapClass()
                stack.pushRef(ref)
            else:
                raise ValueError('Unknown constant type: %s' % type(constant))
